#include <string>
#include <pthread.h>
#include <unistd.h>
#include "UdpServer.hpp"
#include "Thread.hpp"

using namespace myThread;


struct sockaddr_in peer;
pthread_t id;
int socket_fd;
uint16_t server_port;
std::string server_ip;

void recv_msg(){
    while(1){
        struct sockaddr_in get_peer; //还是需要获取一下发送信息来的服务器的ip和端口号
        socklen_t len = sizeof(get_peer);
            //因为有可能一台机器和多态服务器通信，所以需要接收！

        char recv_msg[1024] = {0};
        int m = recvfrom(socket_fd, recv_msg, sizeof(recv_msg) - 1, 0, (struct sockaddr*)&get_peer, &len);
        //std::cout << recv_msg << std::endl;

        //为了实现一种效果：
        //一个窗口只负责发送，回显回到另外一个窗口
        //当然，可以直接绑定死两个显示器文件
        //这里写简单点，让服务器发回来的打印在cerr上，cout和cerr是两个不同的文件！
        //然后，我们把2号(cerr)文件重定向到对应的显示器上，就可以达到上述效果
        std::cerr << recv_msg << std::endl;
        (void)m;
    }
}

void send_msg(){
    
    
    //转为网络序列
    server_port = htons(server_port);

    peer.sin_family = AF_INET;
    peer.sin_port = server_port;
    peer.sin_addr.s_addr = inet_addr(server_ip.c_str());


    //1.向远端服务器发送信息
    while(1){
        std::string send_msg;
        fflush(stdout);
        std::getline(std::cin, send_msg);

        int n = sendto(socket_fd, send_msg.c_str(), send_msg.size(), 0, (struct sockaddr*)&peer, sizeof(peer));
        (void)n;

        if(send_msg == "EXIT"){
            usleep(1000);
            pthread_cancel(id);
            break;
        }
    }
}


//客户端使用的时候也是
// ./UDP_CLIENT  server_port server_ip（因为服务器和客户端是同一家公司写的！）
int main(int argc, char* argv[]){
    if(argc != 3) {
        std::cerr << "please usage : " << "./UDP_SERVER port ip" << std::endl;
        return 1;
    }

    //1.创建socket
    socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(socket_fd < 0){
        std::cerr << "client : socket create error" << std::endl;
    } 

    server_port = std::stoi(std::string(argv[1]));
    server_ip = argv[2];


    //创建两个线程
    Thread Recv(recv_msg);
    Thread Send(send_msg);

    id = Recv.GetTid();

    Recv.Start();
    Send.Start();

    Recv.Join();
    Send.Join();


    //像下面这样写会出问题，到时候可以演示，这里就不删除了(因为必须现发信息出去，才能读取，会阻塞！)
    //本身socket通信就能全双工，所以，完全可以使用两个线程在操作，同时收发！
    /* while(1){
        //1.向远端服务器发送信息
        std::string send_msg;
        std::cout << "please input: " ;
        fflush(stdout);
        std::getline(std::cin, send_msg);
        
        int n = sendto(socket_fd, send_msg.c_str(), send_msg.size(), 0, (struct sockaddr*)&peer, sizeof(peer));
        (void)n;

        struct sockaddr_in get_peer; //还是需要获取一下发送信息来的服务器的ip和端口号
        socklen_t len = sizeof(get_peer);
        //因为有可能一台机器和多态服务器通信，所以需要接收！

        char recv_msg[1024] = {0};
        int m = recvfrom(socket_fd, recv_msg, sizeof(recv_msg) - 1, 0, (struct sockaddr*)&get_peer, &len);
        std::cout << recv_msg << std::endl;
        (void)m;
    } */


    return 0;
}